package neiltwist.cfd.akka;

import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;

public class CFDRunner {

	private final CFDSolver cfdEngine = new CFDSolver();
	private final int windowLimitX = 512;
	private final int windowLimitY = 512;
	
	private long ITERATIONS = 4096;
	
	private int clickStartX, clickStartY;
	private final List<ClickAction> clickList = new ArrayList<ClickAction>();


	public CFDRunner() {

		// create the environment to run in.
		final WindowImpl window = new WindowImpl("NCFD");
		JFrame frame = window.getFrame();
		Image image = new Image();


		frame.getContentPane().add(image, BorderLayout.CENTER);		
		window.showGUI();

		image.addMouseListener(new MouseListener(){
			@Override
			public void mouseClicked(MouseEvent arg0) {
				// Only look at right mouse button
				if(arg0.getButton()==MouseEvent.BUTTON3) {
					ClickAction thisClick = new ClickAction();
					thisClick.setClickXStart(arg0.getX());
					thisClick.setClickYStart(arg0.getY());
					thisClick.setClickType(ClickType.RIGHT);
					clickList.add(thisClick);
				}
			}
			@Override
			public void mouseEntered(MouseEvent arg0) {}
			@Override
			public void mouseExited(MouseEvent arg0) {}
			@Override
			public void mousePressed(MouseEvent arg0) {
				// Only look at left button
				if(arg0.getButton()==MouseEvent.BUTTON1) {
					clickStartX=arg0.getX();
					clickStartY=arg0.getY();
				}
			}
			@Override
			public void mouseReleased(MouseEvent arg0) {
				// Only look at left button
				if(arg0.getButton()==MouseEvent.BUTTON1) {
					ClickAction thisClick = new ClickAction();
					thisClick.setClickXStart(clickStartX);
					thisClick.setClickYStart(clickStartY);
					thisClick.setClickXFinish(arg0.getX());
					thisClick.setClickYFinish(arg0.getY());
					thisClick.setClickType(ClickType.LEFT);
					clickList.add(thisClick);
				}
			}
		});

		go(frame, image);

	}

	private void go(JFrame frame, Image image) {

		long frames = ITERATIONS;

		/**
		 *  Loop through some stuff
		 */
		long frameTime = 0;
		long startTime = System.currentTimeMillis();

		int counter = 0;

		for (int t=1 ; t<frames; t++){
			counter++;
			//        while(true) {
			long frameStartTime = System.currentTimeMillis();
					
			image.reset();
			setPixels(image);
			frame.repaint();
			

			long frameEndTime = System.currentTimeMillis();

			frameTime += (frameEndTime - frameStartTime);

			if(counter >= 1024) {
				System.out.println(t);
				counter=0;
			}
		}

		long endTime = System.currentTimeMillis();

		long timeTaken = endTime - startTime;

		System.out.println("average frame time = " + (frameTime / frames));
		System.out.println(String.format("frame rate = %f, calcd from %d %d",(frames / (timeTaken / 1000f)),frames, timeTaken));
	}

	private void setPixels(Image image){
		/**
		 * The business logic for this code:
		 */
		
		for (ClickAction ca : clickList) {
			cfdEngine.addClick(ca,windowLimitX);
		}
		clickList.clear();

		// take the next step in the CFD engine
		cfdEngine.step();

		// get the value for each pixel and paint it...
		int gridLength = cfdEngine.getGridSize();
		int h = windowLimitX / gridLength;
		for (int x=0 ; x<gridLength; x++){
			for (int y=0 ; y<gridLength; y++){

				/*for (int a=0; a<h; a++) {
					image.process(h*x+a,h*y,0.25f);
				}
				for (int b=0; b<h; b++) {
					image.process(h*x,h*y+b,0.25f);
				}*/

				
				// Get the density
				float nval = cfdEngine.getDensityValue(x, y);
				
				for (int a=0; a<h; a++) {
					for (int b=0; b<h; b++) {
						image.process(h*x+a,h*y+b,nval);
					}
				}
				
				//int i = h*x+h/2;
				//int j = h*y+h/2;
				//image.process(i,j,nval);
				
				int i = (int)(h * (x-0.5f));
				int j = (int)(h * (y-0.5f));

				// Get the velocity field
				float u = cfdEngine.getVelocityUValue(x, y);
				float v = cfdEngine.getVelocityVValue(x, y);
				if( u>0.000000000000000001f || v>0.00000000000000001f) {
//					System.out.println("mag is "+u+" "+v);
					
					image.processRedLine(i,j,(int)(i+u),(int)(j+v));
				}
			}
		}
		
	}


	public static void main(String[] args){
		new CFDRunner();
	}

}
